﻿using BCCommon.PaymentEnums;
using BCData.Sim.Admin.Admin;
using BCData.TMS.Agent.AgentRecord;
using BCDto.Common.Payment.Payment;
using BCDto.Common.Payment.PaymentRecord;
using BCDto.Sim.Admin.Admin;
using BCDto.TMS.Agent.AgentRecord;
using BCDto.Website.User;
using BCService.Common.Payment.Payment;
using BCService.Common.Payment.PaymentCallbackRecord;
using BCService.Common.Payment.PaymentRecord;
using BCService.Utils;
using BCService.Website.User;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace BCTMSRESTful.Controllers.Anonymous
{
    /// <summary>
    /// 支付通用接口
    /// </summary>
    [Route("api/v1/[controller]")]
    public class PaymentsController : BCTMSRESTfulAPIController
    {
        private readonly IPaymentService paymentService;
        private readonly IUserService userService;
        private readonly ICommonPaymentCallbackRecordService commonPaymentCallbackRecordService;
        private readonly ICommonPaymentRecordService commonPaymentRecordService;
        private readonly IAgentRecordData agentRecordData;
        private readonly IAdminData adminData;
        public PaymentsController(IPaymentService paymentService,
            IUserService userService,
            ICommonPaymentCallbackRecordService commonPaymentCallbackRecordService,
            ICommonPaymentRecordService commonPaymentRecordService,
            IAgentRecordData agentRecordData,
            IAdminData adminData)
        {
            this.paymentService = paymentService;
            this.userService = userService;
            this.commonPaymentCallbackRecordService = commonPaymentCallbackRecordService;
            this.commonPaymentRecordService = commonPaymentRecordService;
            this.agentRecordData= agentRecordData;
            this.adminData = adminData;
        }

        #region 接收付款异步通知
        /// <summary>
        /// 接收付款异步通知。
        /// </summary>
        /// <param name="channelId">付款渠道编号。</param>
        /// <param name="paymentRecordId">支付记录Id。</param>
        /// <response code="200">已正确接收异步通知。</response>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("[action]/{channel_id}/{payment_record_id}"), HttpPost("[action]/{channel_id}/{payment_record_id}")]
        public IActionResult ReceiveNotification([FromRoute(Name = "channel_id")] PaymentChannelType channelId, [FromRoute(Name = "payment_record_id")] long paymentRecordId)
        {
            //记录回调通知的参数
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
           
            if (this.Request.Method == "GET")
            {
                Log(string.Format("收到Get回调：{0}",channelId));
                foreach (var item in this.Request.Query)
                {
                    dictionary.Add(item.Key, item.Value);
                }
                Log(JsonConvert.SerializeObject(Request.Query));
            }
            else
            {
                Log(string.Format("收到Post回调：{0}", channelId));
               
                if (this.Request.HasFormContentType)
                {
                    Log(string.Format("收到Post回调Form：{0}", channelId));
                    Log(JsonConvert.SerializeObject(Request.Form));
                    foreach (var item in this.Request.Form)
                    {
                        dictionary.Add(item.Key, item.Value);
                    }
                }

                if (this.Request.ContentLength > 0 && !dictionary.Any())
                {
                    Log(string.Format("收到Post回调FormBody：{0}", channelId));
                    Stream stream = HttpContext.Request.Body;
                    byte[] buffer = new byte[Request.ContentLength.Value];

                    Task<int> streamResultTask = stream.ReadAsync(buffer, 0, buffer.Length);
                    int streamResult = streamResultTask.GetAwaiter().GetResult();
                    dictionary.Add("Request-Body", Encoding.UTF8.GetString(buffer));
                    Log(JsonConvert.SerializeObject(dictionary));
                }
            }

            string dataParameters = string.Join("&", dictionary.Select(p => $"{p.Key}={p.Value}"));
            PaymentRecordDto paymentRecordDto = commonPaymentRecordService.GetPaymentRecord(paymentRecordId);
            long? paymentCallbackRecordId = null;
            UserDto user = null;
            AdminDto admin = null;
            Log(JsonConvert.SerializeObject(paymentRecordDto));
            if (paymentRecordDto.OperationType.HasValue && paymentRecordDto.OperationType == PaymentOperationType.Transfer)
            {
                if (!paymentRecordDto.UserId.HasValue && !paymentRecordDto.AdminId.HasValue)
                {
                    Log(dataParameters);
                    //支付记录无用户Id时，仅存在转账提现接口。
                    SourceAppType appType = paymentRecordDto.AppType;
                    IChannelFactoryService channelService = this.paymentService.GetChannelService(appType, channelId, SourceOSType.Android);
                    ReceiveNotificationDto result = channelService.ReceiveNotification(dictionary, out var payment);

                    return new ContentResult
                    {
                        StatusCode = result.StatusCode,
                        ContentType = result.ContentType,
                        Content = result.ReturnString
                    };
                }
            }
            if (paymentRecordDto.UserId.HasValue)
            {
                user = this.userService.GetUserByUserId(paymentRecordDto.UserId.Value);
                if (user == null)
                {
                    throw new ArgumentException("找不到匹配的用户信息。");
                }
                paymentCallbackRecordId = this.commonPaymentCallbackRecordService.Add(channelId, paymentRecordDto.UserId.Value, dataParameters);
            }
            else
            {

                var agentRecord = agentRecordData.GetEntity(paymentRecordDto.ReferenceNumber.ToLong()).Result;
                if (agentRecord == null)
                {
                    throw new ArgumentException(" 获取代理商信息失败 ");
                }
                admin = adminData.GetAdminByAgentRecordId(agentRecord.AgentRecordId).Result.As<AdminDto>();
                if (admin == null)
                {
                    throw new ArgumentException(" 获取代理商负责人信息失败 ");
                }
                admin.AgentRecord = agentRecord.As<AgentRecordDto>();
                paymentCallbackRecordId = this.commonPaymentCallbackRecordService.AgentAdd(channelId, admin.AdminId, dataParameters);
            }
            if (!paymentCallbackRecordId.HasValue)
            {
                throw new ArgumentException(" 添加支付回调记录失败 ");
            }
            try
            {
                SourceAppType appType = paymentRecordDto.AppType;
                IChannelFactoryService channelService = this.paymentService.GetChannelService(appType, channelId, SourceOSType.Android);
                ReceiveNotificationDto result = channelService.ReceiveNotification(dictionary, out var payment);
                if (channelId == PaymentChannelType.Alipay)
                {
                    if (dictionary["trade_status"] == "TRADE_CLOSED" && Convert.ToDecimal(dictionary["refund_fee"]) > 0)
                    {
                        paymentRecordDto = commonPaymentRecordService.GetRefundPaymentRecord(paymentRecordDto.ReferenceNumber);
                    }
                }

                //如果用户手动调用过验签，这里就跳过，这里是业务没有验签时走的.
                //TODO:最终需要重新根据订单情况，重新设计这里的整套逻辑
                if (paymentRecordDto.CheckSignTime == null && payment.Result == PaymentResultType.Success)
                {
                    if (paymentRecordDto.OperationType == PaymentOperationType.Refund)
                    {
                        this.commonPaymentRecordService.InsertRefundRecord(paymentRecordDto);
                    }
                    else
                    {
                        if (user != null)
                        {
                            this.paymentService.Synchronize(user, paymentRecordDto);
                        }
                        else if (admin!=null)
                        {
                            this.paymentService.AgentSynchronize(admin, paymentRecordDto);
                        }

                    }
                }

                this.commonPaymentCallbackRecordService.UpdateStatus(paymentCallbackRecordId.Value);

                return new ContentResult
                {
                    StatusCode = result.StatusCode,
                    ContentType = result.ContentType,
                    Content = result.ReturnString
                };
            }
            catch (Exception ex)
            {
                this.commonPaymentCallbackRecordService.UpdateRemakeContent(paymentCallbackRecordId.Value, string.Format("{0}---{1}", ex.Message, ex.InnerException));

                throw;
            }
        }
        #endregion

        #region 手动触发付款异步通知--测试使用
        /// <summary>
        /// 手动触发付款异步通知--测试使用。
        /// </summary>
        /// <param name="channelId">付款渠道编号。</param>
        /// <param name="userId">用户编号。</param>
        /// <response code="200">已正确接收异步通知。</response>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("[action]/{channel_id}/{user_id}"), HttpPost("[action]/{channel_id}/{user_id}")]
        public IActionResult ManualReceiveNotification([FromRoute(Name = "channel_id")]PaymentChannelType channelId, [FromRoute(Name = "user_id")]long userId)
        {
            Dictionary<string, string> dictionary = new Dictionary<string, string>();

            if (this.Request.Method == "GET")
            {
                foreach (var item in this.Request.Query)
                {
                    dictionary.Add(item.Key, item.Value);
                }
            }
            else
            {
                if (this.Request.HasFormContentType)
                {
                    foreach (var item in this.Request.Form)
                    {
                        dictionary.Add(item.Key, item.Value);
                    }
                }

                if (this.Request.ContentLength > 0 && !dictionary.Any())
                {
                    byte[] buffer = new byte[Request.ContentLength.Value];

                    this.Request.Body.Read(buffer, 0, buffer.Length);

                    dictionary.Add("Request-Body", Encoding.UTF8.GetString(buffer));
                }
            }

            _ = userService.GetUserByUserId(userId);

            SourceAppType appType = SourceAppType.ClientApp;

            //if (user.Role == RoleType.Driver)
            //{
            //    appType = SourceAppType.DriverApp;
            //}
            //else if (user.Role == RoleType.Partner)
            //{
            //    appType = SourceAppType.PartnerApp;
            //}

            IChannelFactoryService channelService = this.paymentService.GetChannelService(appType, channelId, SourceOSType.Android);
            var result = channelService.ReceiveNotification(dictionary, out _);

            return new ContentResult
            {
                StatusCode = result.StatusCode,
                ContentType = result.ContentType,
                Content = result.ReturnString
            };
        }
        #endregion

        #region 日志
        private void Log(string str)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());
            string path = Path.Combine(directoryInfo.FullName, "PaymentCallbackRecord", DateTime.Now.ToString("yyyy-MM-dd"));
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            FileInfo fileInfo = new FileInfo(Path.Combine(path, "PaymentCallbackRecord.txt").ToString());
            Console.WriteLine("*****************************************");
            Console.WriteLine(str);
            if (!fileInfo.Exists)
            {
                using (StreamWriter sw = fileInfo.CreateText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    sw.WriteLine("{0}", str);
                }
            }
            else
            {
                using (StreamWriter sw = fileInfo.AppendText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    sw.WriteLine("{0}", str);
                }
            }
        }
        #endregion
    }
}
